package middleware

import (
	"gostore/common"
	"gostore/dao/system"
	"gostore/model"
	"gostore/util"
	"gostore/util/log"
	"strings"

	jwt "github.com/dgrijalva/jwt-go"

	"github.com/gin-gonic/gin"

	"time"
)

var jwtSecret = []byte("secret-key")

type Claims struct {
	Username string `json:"username"`
	Password string `json:"password"`
	RoleName string `json:"roleName"`
	jwt.StandardClaims
}

var defaultDuration = 3 * time.Hour
var defaultIssuer = "gostore"

//generate token
func GenerateToken(username, password, roles string) (string, error) {
	l := log.Factory(GenerateToken)

	currTime := time.Now()
	expireTime := currTime.Add(defaultDuration)

	l.Debug("promulgate token")
	//build jwt
	claims := Claims{
		username,
		password,
		roles,
		jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    defaultIssuer,
		},
	}

	//generate jwt
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	//generate complete token
	token, err := tokenClaims.SignedString(jwtSecret)

	return token, err
}

func ParseToken(token string) (*Claims, error) {
	l := log.Factory(ParseToken)

	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})

	if tokenClaims != nil {
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			l.Debug("valid claims", claims)
			return claims, nil
		}
	}
	log.Debug("valid claims fail")
	return nil, err
}

var defaultToken = "X-Token"

//jwt 登录认证
func JWT() gin.HandlerFunc {
	l := log.Factory(JWT)

	return func(c *gin.Context) {
		request := c.Request
		path, method := request.URL.Path, request.Method
		l.Debug("request", path, method)

		token := c.GetHeader(defaultToken)

		if token == "" {
			token = c.Query(defaultToken)
		}
		if token != "" {
			claims, err := ParseToken(token)
			l.Debug(claims, err)

			if err == nil && claims != nil && time.Now().Unix() < claims.ExpiresAt {
				//注入账户名
				c.Set("account", claims.Username)
				c.Set("roles", claims.RoleName)

				// c.Request
				c.Next()
				return
			}
		}

		common.ErrUnauth(c, "无效的token")
		c.Abort()
	}
}

const (
	Md5Salt = "gostore"
)

func Login(c *gin.Context) {

	admin := model.SystemAdmin{}
	err := c.ShouldBindJSON(&admin)

	if err != nil {
		common.Err(c, 1, err.Error())
		return
	}
	account := admin.Account
	pwd := admin.Pwd

	log.Debug("user login", account, pwd)

	if len(account) > 0 && len(pwd) > 0 {
		adminNew := model.SystemAdmin{}
		pwdMd5 := util.ToMd5WithSalt(pwd, Md5Salt)
		err := system.AdminDao.Login(&adminNew, account, pwdMd5)
		if err == nil {
			token, err := GenerateToken(account, pwdMd5, adminNew.Roles)
			if err != nil {
				common.Err(c, 1, err.Error())
				return
			}
			adminNew.Pwd = ""
			common.Ok(c, map[string]interface{}{
				"token": token,
				"admin": adminNew,
			})
			return
		}
	}
	common.Err(c, 1, "用户名或密码错误")
}

//权限验证
func Auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		roles, exists := c.Get("roles")
		if exists {
			if str, ok := roles.(string); ok {
				roleList := strings.Split(str, ",")
				path, method := c.Request.URL.Path, c.Request.Method

				auth := GetAuthManager()
				if auth.Check(roleList, path, method) {
					c.Next()
					return
				}
			}
		}
		common.ErrUnauth(c, "您没有访问权限，请联系管理员")
		c.Abort()
	}
}
